#include "log.hpp"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <strings.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>

using namespace std;
using func_t = function<string(string)>;

enum ErrorInfo
{
    SOCKET_CREATE = 1,
    SOCKET_BIND
};

class Analyze
{
public:
    Analyze(struct sockaddr_in addr)
        :_addr(addr)
    {
        analyze(_ip, _port);
    }

    string GetIp()
    {
        return _ip;
    }

    uint16_t GetPort()
    {
        return _port;
    }

private:
    void analyze(string &_ip, uint16_t& _port)
    {
        _ip = inet_ntoa(_addr.sin_addr);  //将4字节ip地址从网络序列转为主机序列，并转化为char*返回
        _port = ntohs(_addr.sin_port);
    }

    struct sockaddr_in _addr;
    string _ip;
    uint16_t _port;

};



class Udpserver
{
private:
    uint16_t _port;
    uint32_t _sockfd;
    bool _running = false;

    func_t _func;

public:
    Udpserver(uint16_t port, func_t func)
        :_port(port)
        ,_func(func)
    {};

    void init()
    {
        // 1. 创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
        if(_sockfd < 0)
        {
            cerr << "socket create fail" << endl;
            exit(SOCKET_CREATE);
        }
        cout << "socket create sucess" << " socketfd = " << _sockfd << endl;

        // 2. 绑定socket和网络信息

        // 2.1 填充struct sockaddr结构
        struct sockaddr_in local;
        bzero(&local, 0);       
        local.sin_family = AF_INET; 
        local.sin_addr.s_addr = 0;       //匹配本机任意ip地址，(IP地址也需要转为网络地址，inet_addr(_ip.c_str())，将ip字符串转为整型4字节，再转为网络序列)
        local.sin_port = htons(_port);   //port主机序列转网络序列

        // 2.2 绑定
        int bind_val = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
        if(bind_val < 0)
        {
            cerr << "socket bind fail" << endl;
            exit(SOCKET_BIND);
        }
        cout << "socket bind success" << endl;

        //初始化完成
        Log(Info, "init success");
    }

    void start()
    {
        _running = true;
        char buffer[1024];
        while(true)
        {           
            bzero(buffer, sizeof(buffer));

            struct sockaddr_in peer;
            bzero(&peer, 0);
            socklen_t len = sizeof(peer);

            //先使服务端接收信息
            ssize_t ref = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
            if(ref > 0)
            {
                //解析客户端发来的信息
                Analyze ana(peer);
                //日志信息

                // buffer[ref] = 0;
                Log(Info, "get message from: %s, port: %d, infomation: %s\n", ana.GetIp(), ana.GetPort(), buffer);
                //将消息发回客户端, 需要知道发给谁
               
                string response = _func(buffer);
                sendto(_sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&peer, len);
            }
        }
        _running = false;
    }

    ~Udpserver()
    {}
};
